xquery version "1.0";

module namespace ranking="http://www.example.com/ranking";

declare namespace request="http://exist-db.org/xquery/request";
declare namespace response="http://exist-db.org/xquery/response";
declare namespace session="http://exist-db.org/xquery/session";
declare namespace xdb="http://exist-db.org/xquery/xmldb";

declare function local:displayItem($tupel, $cost)
{
    element li {
        attribute ref {$tupel/@ref},
        element role {concat(if (data($tupel/role) != '') then data($tupel/role) else 'mp', 'Role', if (data($tupel/mayor) = 'TRUE') then ' mayorRole' else ())},
        element value {data($cost)},
        element name {data($tupel/speaker)},
        element party {data($tupel/pparty)},
        element sex {data($tupel/sex)},
        element mayor {data($tupel/mayor)}
    }
};

declare function local:partialCost($param, $value)
{
    let $weight := xs:double(request:get-parameter($param, 0))
    let $nWeight := if ($weight < 0) then 0 else if ($weight > 1) then 1 else $weight   

    return ($value*$nWeight*100)
};

(: return the index of a specified node in a list of nodes :)
declare function local:index-of-node($nodes, $nodeToFind)
{       
  for $seq in (1 to count($nodes))
  return $seq[$nodes[$seq] = $nodeToFind]
 };

declare function local:cost($tupel, $tupels)
{
    let $maxPresent := max(data($tupels/present))
    let $maxInitiatedTopics := max(data($tupels/initiatedTopics))
    let $maxParticipatedTopics := max(data($tupels/participatedTopics))
    let $maxInteruptions := max(data($tupels/interuptions))
    let $maxWordCount := max(data($tupels/avgNumberOfWords))
    let $maxInitiatedParticipation :=max(data($tupels/initiatedParticipatedTopics))

    let $participationValue := local:partialCost("participation", number($tupel/participatedTopics) div $maxParticipatedTopics)
    let $initiatorValue := local:partialCost("initiator", number($tupel/initiatedTopics) div $maxInitiatedTopics)
    let $presentValue := local:partialCost("present", number($tupel/present) div $maxPresent)
    let $interuptionValue := local:partialCost("interuption", number($tupel/interuptions) div $maxInteruptions)
    let $wordCountValue := local:partialCost("wordCount", number($tupel/avgNumberOfWords) div $maxWordCount)
    let $initiatedParticipationValue := local:partialCost("initiatedParticipation", number($tupel/initiatedParticipatedTopics) div $maxInitiatedParticipation)

    return (xs:double($presentValue) + xs:double($wordCountValue) + xs:double($participationValue) + xs:double($initiatorValue) + xs:double($initiatedParticipationValue) + xs:double($interuptionValue)) div (xs:double(request:get-parameter("participation", 0)) + xs:double(request:get-parameter("initiator", 0)) + xs:double(request:get-parameter("present", 0)) + xs:double(request:get-parameter("interuption", 0)) + xs:double(request:get-parameter("wordCount", 0)) + xs:double(request:get-parameter("initiatedParticipation", 0)))
};

(: calculate average, avoids div by zero :)
declare function local:safe-avg($nodes) {
    let $count := count($nodes)
    return if ($count = 0) then sum($nodes)
        else sum($nodes) div $count
};

declare function local:group_stats($tupels, $list, $elementName) {
    (: every political party :)
    let $distinct-names := distinct-values(data($tupels/*[name() = $elementName]))
    return element group {
        attribute id { concat($elementName, "Stats") },
    for $name in $distinct-names
        let $distinct-person-names := distinct-values(data($tupels[data(./*[name() = $elementName]) = $name]/speaker))
        let $rankings := document {for $li in $list/li
                                    where count($distinct-person-names[. = data($li/name)]) = 1
                                    return $li
                                    }
        let $max-ranking-value := max(data($rankings/li/@ranking))
        return element item {
            element name { $name },
            element minValue {min($rankings/li/value)},
            element maxValue {max($rankings/li/value)},
            element avgValue {local:safe-avg($rankings/li/value)},
            
            element minRanking {min($rankings/li/@ranking)},
            element maxRanking {max($rankings/li/@ranking)},
            element avgRanking {local:safe-avg($rankings/li/@ranking)},
            
            element firstPart {count($rankings/li[data(@ranking) <= ($max-ranking-value div 4)])},
            element secondPart {count($rankings/li[data(@ranking) <= ($max-ranking-value div 2) and data(@ranking) > ($max-ranking-value div 4)])},
            element thirdPart {count($rankings/li[data(@ranking) <= ($max-ranking-value div 4 * 3) and data(@ranking) > ($max-ranking-value div 2)])},
            element fourthPart {count($rankings/li[data(@ranking) > ($max-ranking-value div 4*3)])}
        }
    }
};

declare function ranking:create_rankingList($parameters) {
    let $tupels := $parameters/result/tupel


    let $list := document {
            for $tupel in $tupels
                let $cost := local:cost($tupel, $tupels)
                where ((contains(data($tupel/role),'mp') or not(data($tupel/role))) and request:get-parameter("includeMP", "false") = "true")
                    or (contains(data($tupel/role),'government') and request:get-parameter("includeGovernment", "false") = "true")
                    or (contains(data($tupel/role), 'chair') and request:get-parameter("includeChair", "false") = "true")
                order by $cost descending
                return local:displayItem($tupel, $cost)
        }
        
    let $distin-v := distinct-values(data($list/li/value))
    let $ranked_list := document {
            for $tupel in $list/li
                return element li {
                    attribute ranking {local:index-of-node($distin-v, $distin-v[data(.) = data($tupel/value)])},
                    attribute ref {$tupel/@ref},
                    $tupel/role,
                    $tupel/value,
                    $tupel/name,
                    $tupel/party,
                    $tupel/sex,
                    $tupel/mayor
                }
        }

    return element root {
        element group_stats {
            local:group_stats($tupels, $ranked_list, "pparty"),
            local:group_stats($tupels, $ranked_list, "sex"),
            local:group_stats($tupels, $ranked_list, "mayor")
        },
        $ranked_list,
        element maxIndiRanking { max($ranked_list//li/@ranking) }
    }
};



declare function local:partialDisplayItem($tupel, $cost)
{
    element li {
        attribute ref {$tupel/@ref},
        (:element role {concat(if (data($tupel/role) != '') then data($tupel/role) else 'mp', 'Role', if (data($tupel/mayor) = 'TRUE') then ' mayorRole' else ())},:)
        element value {data($cost)},
        element name {data($tupel/speaker)}
        (:element party {data($tupel/pparty)},
        element sex {data($tupel/sex)},
        element mayor {data($tupel/mayor)}:)
    }
};

declare function ranking:create_partialRankingList($parameters) {
    let $tupels := $parameters/result/tupel


    let $list := document {
            for $tupel in $tupels
                let $cost := local:cost($tupel, $tupels)
                where ((contains(data($tupel/role),'mp') or not(data($tupel/role))) and request:get-parameter("includeMP", "false") = "true")
                    or (contains(data($tupel/role),'government') and request:get-parameter("includeGovernment", "false") = "true")
                    or (contains(data($tupel/role), 'chair') and request:get-parameter("includeChair", "false") = "true")
                order by $cost descending
                return local:partialDisplayItem($tupel, $cost)
        }
        
    let $distin-v := distinct-values(data($list/li/value))
    let $ranked_list := document {
            for $tupel in $list/li
                return element li {
                    attribute ranking {local:index-of-node($distin-v, $distin-v[data(.) = data($tupel/value)])},
                    attribute ref {$tupel/@ref},
                    (:$tupel/role,:)
                    $tupel/value,
                    $tupel/name
                    (:$tupel/party,
                    $tupel/sex,
                    $tupel/mayor:)
                }
        }

    return element root {
        (:element group_stats {
            local:group_stats($tupels, $ranked_list, "pparty"),
            local:group_stats($tupels, $ranked_list, "sex"),
            local:group_stats($tupels, $ranked_list, "mayor")
        },:)
        $ranked_list
    }
};

